<template>
  <div class="video-converter">
    <div class="upload-area" @click="triggerFileInput">
      <input
        type="file"
        ref="fileInput"
        @change="handleFileUpload"
        accept="video/*"
        style="display: none"
      />
      <div v-if="!videoFile" class="upload-prompt">
        <span class="icon">📁</span>
        <p>点击上传视频文件</p>
      </div>
      <div v-else class="file-info">
        <p>已选择文件: {{ videoFile.name }}</p>
        <p>大小: {{ (videoFile.size / 1024 / 1024).toFixed(2) }} MB</p>
      </div>
    </div>

    <div class="controls" v-if="videoFile">
      <button @click="convertToHLS" :disabled="isConverting">
        {{ isConverting ? "转换中..." : "转换为HLS格式" }}
      </button>
      <button @click="reset" class="secondary">重置</button>
    </div>

    <div class="progress-container" v-if="isConverting">
      <div class="progress-bar" :style="{ width: progress + '%' }"></div>
      <span>{{ progress }}%</span>
    </div>

    <div class="player-container" v-if="hlsPlaylistUrl">
      <h3>转换结果</h3>
      <video ref="videoPlayer" controls></video>
      <div class="download-links">
        <a :href="hlsPlaylistUrl" download="playlist.m3u8">下载m3u8文件</a>
        <a v-if="tsFiles.length > 0" :href="tsFiles[0]" download>下载示例TS文件</a>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";
import Hls from "hls.js";
import { FFmpeg } from "@ffmpeg/ffmpeg";
import { fetchFile } from "@ffmpeg/util";

// 类型定义
interface FFmpegProgress {
  ratio: number;
}

// Refs
const fileInput = ref<HTMLInputElement | null>(null);
const videoPlayer = ref<HTMLVideoElement | null>(null);
const videoFile = ref<File | null>(null);
const isConverting = ref<boolean>(false);
const progress = ref<number>(0);
const hlsPlaylistUrl = ref<string | null>(null);
const tsFiles = ref<string[]>([]);
let hlsInstance: Hls | null = null;

// 创建FFmpeg实例
const ffmpeg = new FFmpeg();
let isFFmpegLoaded = false;

// 初始化FFmpeg
const initFFmpeg = async (): Promise<void> => {
  if (!isFFmpegLoaded) {
    await ffmpeg.load({
      coreURL: "https://unpkg.com/@ffmpeg/core@0.12.6/dist/ffmpeg-core.js",
    });
    isFFmpegLoaded = true;
  }
};

// 触发文件选择
const triggerFileInput = (): void => {
  if (fileInput.value) {
    fileInput.value.click();
  }
};

// 处理文件上传
const handleFileUpload = (e: Event): void => {
  const target = e.target as HTMLInputElement;
  const file = target.files?.[0];
  if (file) {
    videoFile.value = file;
  }
};

// 转换视频为HLS格式
const convertToHLS = async (): Promise<void> => {
  if (!videoFile.value) return;

  isConverting.value = true;
  progress.value = 0;

  try {
    // 初始化FFmpeg
    await initFFmpeg();

    // 设置进度监听
    ffmpeg.on("progress", ({ progress: currentProgress }: { progress: number }) => {
      progress.value = Math.round(currentProgress * 100);
    });

    const inputName = "input.mp4";
    const outputName = "output.m3u8";

    // 写入输入文件
    await ffmpeg.writeFile(inputName, await fetchFile(videoFile.value));

    // 执行转换命令
    await ffmpeg.exec([
      "-i",
      inputName,
      "-c:v",
      "libx264",
      "-c:a",
      "aac",
      "-hls_time",
      "10",
      "-hls_list_size",
      "0",
      "-hls_segment_filename",
      "segment_%03d.ts",
      "-f",
      "hls",
      outputName,
    ]);

    // 读取m3u8播放列表
    const playlistData = await ffmpeg.readFile(outputName);
    // 处理不同的返回类型
    let playlistBlob: Blob;

    if (typeof playlistData === "string") {
      // 如果是字符串内容
      playlistBlob = new Blob([playlistData], {
        type: "application/vnd.apple.mpegurl",
      });
    } else {
      // 如果是二进制数据 (Uint8Array)
      playlistBlob = new Blob([playlistData], {
        type: "application/vnd.apple.mpegurl",
      });
    }

    hlsPlaylistUrl.value = URL.createObjectURL(playlistBlob);

    // 获取所有文件列表并筛选TS文件
    const files = await ffmpeg.listDir("/");
    const tsFileNames = files
      .filter((file) => file.isFile && file.name.endsWith(".ts"))
      .map((file) => file.name);

    // 读取TS文件并创建URL
    const tsUrls = [];
    for (const fileName of tsFileNames) {
      const data = await ffmpeg.readFile(fileName);
      const blob = new Blob([data], { type: "video/MP2T" });
      tsUrls.push(URL.createObjectURL(blob));
    }
    tsFiles.value = tsUrls;

    // 初始化播放器
    initPlayer();
  } catch (error) {
    console.error("转换失败:", error);
    alert("视频转换失败，请查看控制台获取详细信息");
  } finally {
    isConverting.value = false;
  }
};

// 初始化HLS播放器
const initPlayer = (): void => {
  if (!videoPlayer.value || !hlsPlaylistUrl.value) return;

  if (Hls.isSupported()) {
    hlsInstance = new Hls();
    hlsInstance.loadSource(hlsPlaylistUrl.value);
    hlsInstance.attachMedia(videoPlayer.value);
    hlsInstance.on(Hls.Events.MANIFEST_PARSED, () => {
      videoPlayer.value?.play().catch(console.error);
    });
  } else if (videoPlayer.value.canPlayType("application/vnd.apple.mpegurl")) {
    // Safari原生支持
    videoPlayer.value.src = hlsPlaylistUrl.value;
    videoPlayer.value.addEventListener("loadedmetadata", () => {
      videoPlayer.value?.play().catch(console.error);
    });
  }
};

// 重置组件状态
const reset = (): void => {
  videoFile.value = null;
  hlsPlaylistUrl.value = null;
  tsFiles.value = [];
  progress.value = 0;
  if (hlsInstance) {
    hlsInstance.destroy();
    hlsInstance = null;
  }
  if (fileInput.value) {
    fileInput.value.value = "";
  }

  // 清理FFmpeg文件系统
  if (isFFmpegLoaded) {
    ffmpeg.off("progress"); // 移除进度监听
  }
};

// 组件卸载时清理
onUnmounted(() => {
  reset();

  // 释放Blob URL
  if (hlsPlaylistUrl.value) {
    URL.revokeObjectURL(hlsPlaylistUrl.value);
  }
  tsFiles.value.forEach((url) => URL.revokeObjectURL(url));
});
</script>

<style scoped>
/* 样式保持不变 */
.video-converter {
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
  font-family: "Arial", sans-serif;
}

.upload-area {
  border: 2px dashed #ccc;
  border-radius: 8px;
  padding: 40px;
  text-align: center;
  cursor: pointer;
  margin-bottom: 20px;
  transition: all 0.3s;
}

.upload-area:hover {
  border-color: #42b983;
  background-color: #f8f8f8;
}

.upload-prompt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.icon {
  font-size: 48px;
}

.file-info {
  text-align: left;
}

.controls {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
}

button {
  padding: 10px 20px;
  background-color: #42b983;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s;
}

button:hover {
  background-color: #369f6e;
}

button:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}

button.secondary {
  background-color: #f0f0f0;
  color: #333;
}

button.secondary:hover {
  background-color: #e0e0e0;
}

.progress-container {
  width: 100%;
  background-color: #f0f0f0;
  border-radius: 4px;
  margin-bottom: 20px;
  position: relative;
  height: 24px;
}

.progress-bar {
  height: 100%;
  background-color: #42b983;
  border-radius: 4px;
  transition: width 0.3s;
}

.progress-container span {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: white;
  font-weight: bold;
}

.player-container {
  margin-top: 30px;
}

.player-container h3 {
  margin-bottom: 15px;
}

video {
  width: 100%;
  max-height: 500px;
  background-color: #000;
  border-radius: 8px;
}

.download-links {
  margin-top: 15px;
  display: flex;
  gap: 15px;
}

.download-links a {
  color: #42b983;
  text-decoration: none;
  font-weight: bold;
}

.download-links a:hover {
  text-decoration: underline;
}
</style>
